(() => {
  const API_TOKEN_BH = 'http://dc.exweixin.com/index.php?app=weixin&mod=TemplateMessage&act=getToken';
  const API_TOKEN_GET = 'https://api.weixin.qq.com/cgi-bin/token';
  const API_TEMPLATE_MESSAGE_SEND = 'https://api.weixin.qq.com/cgi-bin/message/template/send';
  const API_TEMPLATE_MESSAGE_GET_ALL_PRIVATE_TEMPLATE = 'https://api.weixin.qq.com/cgi-bin/template/get_all_private_template';

  class Wechat {
    constructor($http, $httpParamSerializerJQLike, $exception, $settings) {
      this.$http = $http;
      this.$httpParamSerializerJQLike = $httpParamSerializerJQLike;
      this.$exception = $exception;
      this.$settings = $settings;
    }
    token (refresh) {
      return new Promise((resolve, reject) => {
        this.$settings.get().then((result) => {
          let settings = result.response;
          console.log(result);
          console.log(settings)
          if (!refresh && settings.credential && settings.credential.access_token && settings.credential.expiration > Date.now()) {
            resolve(settings.credential);
          }
          else if (settings.uid && settings.password) {
            this.$http({
              method: 'POST',
              headers: {'Content-Type': 'application/x-www-form-urlencoded'},
              url: API_TOKEN_BH,
              data: this.$httpParamSerializerJQLike({
                uid: settings.uid,
                password: settings.password
              }),
              responseType: 'json'
            }).then((response) => {
              console.log(response);
              if (response.data.errcode) {
                this.$exception.handle(response);
                reject(response);
              }
              else {
                // 缓存token
                settings = Object.assign({}, settings, {
                  credential: {
                    access_token: response.data.access_token,
                    expiration: response.data.expires_in * 1000 + Date.now()
                  }
                });
                console.log(response);
                this.$settings.put(settings).then((result) => {
                  console.log(result)
                  resolve(settings.credential);
                },
                (error) => {
                  this.$exception.handle(error);
                  resolve(response);
                })
              }
            }, (response) => {
              reject(response);
            });
          }
          else if (settings.appid && settings.appsecret) {
            this.$http({
              method: 'GET',
              url: this.urlBuilder(API_TOKEN_GET, {
                grant_type: 'client_credential',
                appid: settings.appid,
                secret: settings.appsecret
              }),
              responseType: 'json'
            }).then((response) => {
              if (response.data.errcode) {
                this.$exception.handle(response.data);
                reject(response.data);
              }
              else {
                // 缓存token
                settings = Object.assign({}, settings, {
                  credential: {
                    access_token: response.data.access_token,
                    expiration: response.data.expires_in * 1000 + Date.now()
                  }
                });
                this.$settings.put(settings).then((result) => {
                  resolve(settings.credential);
                },
                (error) => {
                  this.$exception.handle(error);
                  resolve(response);
                })
              }
            }, (response) => {
              reject(response.data);
            });
          }
          else {
            reject({
              status: 401,
              statusText: '缺少授权信息' 
            });
          }
        },
        (error) => {
          reject(error);
        })
        
      })
    }
    templates (refresh) {
      return new Promise((resolve, reject) => {
        this.$settings.get().then((result) => {
          let settings = result.response;
          if (!refresh && settings.template_list) {
            resolve(settings.template_list);
          }
          else {
            this.token(true).then((credential) => {
              this.$http({
                method: 'GET',
                url: this.urlBuilder(API_TEMPLATE_MESSAGE_GET_ALL_PRIVATE_TEMPLATE, {
                  access_token: credential.access_token
                }),
                responseType: 'json'
              }).then((response) => {
                if (response.data.errcode) {
                  this.$exception.handle(response.data);
                  reject(response.data);
                }
                else {
                  this.$settings.get().then((result) => {
                    settings = Object.assign({}, result.response, {
                      template_list: response.data.template_list
                    });
                    this.$settings.put(settings).then(() => {
                      resolve(settings.template_list);
                    })
                  },
                  (error) => {
                    reject(error)
                  })
                }
              }, (error) => {
                reject(error);
              });
            },
            (error) => {
              reject(error);
            })
          }
        },
        (error) => {
          reject(error);
        })
      })
    }
    send (message) {
      console.log(message);
      return new Promise((resolve, reject) => {
        this.token().then((credential) => {
          this.$http({
            method: 'POST',
            url: this.urlBuilder(API_TEMPLATE_MESSAGE_SEND, {
              access_token: credential.access_token
            }),
            data: message,
            responseType: 'json'
          }).then((response) => {
            if (response.data.errcode) {
              this.$exception.handle(response.data);
              reject(response.data);
            }
            else {
              resolve(response.data);
            }
          }, (response) => {
            reject(response.data);
          });
        },
        (error) => {
          reject(error);
        })
      })
    }
    urlBuilder (base, parameters) {
      return base + '?' + this.$httpParamSerializerJQLike(parameters);
    }
  }
  angular.module('app').factory('$wechat', ['$http', '$httpParamSerializerJQLike', '$exception', '$settings', ($http, $httpParamSerializerJQLike, $exception, $settings) => new Wechat($http, $httpParamSerializerJQLike, $exception, $settings)]);
})()